/**
 * 给定N+Q个点的无向带权图，一共Q次操作，第i次操作：
 * 将[L, R]中所有的点向 i + N 连权值为 W 的边， [L, R]肯定在N以内
 * 求最后的MST
 * 将[1...N]记作区间点，每次操作的i+N记作锚点。
 * 
 * 考虑Kruskal算法的流程，首先对操作按权值升序排序。
 * 可以发现锚点直接互相不连，必须连在区间上。然后如果区间分为x块，则就有x*W条边要计入MST。然后这些区间就连成了一块。
 * 可以用线段树来维护。注意到肯定不会跨区间连通，因此记录{left, right, cnt}即可，分别是左边界颜色、右边界颜色与段数
 * 每次操作只需要查询 [L, R] 之间的cnt即可。
 * 然后分别向左找到与L连在一起的最远的left，以及向右找到与R连接的最远的right，然后将[left, right]设置成一段即可。
 * O(QlogNlogN)
 * 似乎有只有一个log的做法。
 */
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;

using llt = long long;
using vi = vector<int>;
using vll = vector<llt>;
using pii = pair<int, int>;
using pll = pair<llt, llt>;

struct SegTree{ // 线段树带延迟

struct _t{
    int left;
    int right;
    int cnt;
};

int N;

using value_type = _t;
vector<value_type> data; // 线段树

using lazy_type = int;
vector<lazy_type> lazy; // 延迟标记

/// 从下往上计算信息，要变动
value_type _up_(const value_type & ls, const value_type & rs) {
    if(ls.cnt == 0) return rs;
    if(rs.cnt == 0) return ls;
    return {ls.left, rs.right, ls.cnt + rs.cnt - (ls.right == rs.left ? 1 : 0)};
}

// 根据变动信息delta计算本节点的信息并且打延迟标记，用于pushDown或者modify
// 这里只计算t，跟t的儿子无关
// 要计算data[t]和lazy[t]
void _dn_(int t, int s, int e, const lazy_type & delta) {
    data[t] = {delta, delta, 1};
    lazy[t] = delta;
}

/// 初始化，清零，不用动
void init(int n) {
    data.assign((N = n) + 1 << 2, value_zero());
    lazy.assign(n + 1 << 2, lazy_zero());
}

/// 这个函数不用动
void modify(int a, int b, const lazy_type & delta){
    _modify(1, 1, N, a, b, delta);
}

/// 这个函数不用动
value_type query(int a, int b){
    return _query(1, 1, N, a, b);
}

/// 这个函数不用动
void build() {
    _build(1, 1, N);
}

/// 几乎不用动
value_type _query(int t, int s, int e, int a, int b) {
    if(a <= s and e <= b) {
        return data[t];
    }
    _pushDown(t, s, e);
    int mid = (s + e) >> 1;
    value_type ans = value_zero(); // 如果求最值，这里不能用zero
    if(a <= mid) ans = _up_(ans, _query(lson(t), s, mid, a, b));
    if(mid < b) ans = _up_(ans, _query(rson(t), mid + 1, e, a, b));
    return ans;
}

/// 几乎不用动
void _modify(int t, int s, int e, int a, int b, const lazy_type & delta) {
    if(a <= s and e <= b) {
        _dn_(t, s, e, delta);
        return;
    }
    _pushDown(t, s, e);
    int mid = (s + e) >> 1;
    if(a <= mid) _modify(lson(t), s, mid, a, b, delta);
    if(mid < b) _modify(rson(t), mid + 1, e, a, b, delta);
    _pushUp(t);
    return;
}

/// 这个函数不用动
void _pushUp(int t) {
    data[t] = _up_(data[lson(t)], data[rson(t)]);
}

/// 这个函数几乎不用动
void _pushDown(int t, int s, int e) {
    if(lazy_zero() == lazy[t]) return;
    auto & lz = lazy[t];
    auto ls = lson(t), rs = rson(t);
    int mid = (s + e) >> 1;

    _dn_(ls, s, mid, lz);
    _dn_(rs, mid + 1, e, lz);

    lz = lazy_zero();
}


/// 几乎不用动
void _build(int t, int s, int e) {
    if(s == e) {
        data[t] = {s, s, 1};
        return; 
    }
    int mid = (s + e) >> 1;
    _build(lson(t), s, mid);
    _build(rson(t), mid + 1, e);
    _pushUp(t);
}

/// 辅助函数，视延迟的类型而变动
static const lazy_type & lazy_zero() {
    static const lazy_type LAZY0 = 0;
    return LAZY0; 
}

/// 辅助函数，视线段树信息类型而变动
static const value_type & value_zero() {
    static const value_type VALUE0 = {0, 0, 0};
    return VALUE0;
}

/// 这两个函数不用变动
static int lson(int x) {return x << 1;}
static int rson(int x) {return lson(x) | 1;}


};

struct _t{
    int left;
    int right;
    int w;
    int anchor;
};

int N;
int Q;
SegTree St;
vector<_t> A;

int procLeft(int right){
    int total = St.query(1, right).cnt;

    int left = 1, mid;
    do{
        mid = (left + right) >> 1;
        if(St.query(1, mid).cnt != total) left = mid + 1;
        else right = mid - 1;
    }while(left <= right);
    return left;
}

int procRight(int start){
    int left = start, right = N, mid;
    do{
        mid = (left + right) >> 1;
        if(St.query(start, mid).cnt <= 1) left = mid + 1;
        else right = mid - 1;
    }while(left <= right);
    return right;
}

void work(){
    cin >> N >> Q;
    A.assign(Q, {});
    for(int i=0;i<Q;++i){
        cin >> A[i].left >> A[i].right >> A[i].w;
        A[i].anchor = i + 1 + N;
    }
    
    sort(A.begin(), A.end(), [](const _t & a, const _t & b){
        if(a.w != b.w) return a.w < b.w;
        return a.anchor < b.anchor;
    });

    St.init(N);
    St.build();

    llt ans = 0;
    for(const auto & p : A){
        auto tmp = St.query(p.left, p.right);
        ans += (tmp.cnt + 0LL) * p.w;
        
        int left = procLeft(p.left);
        int right = procRight(p.right);
        St.modify(left, right, tmp.left);
    }
    if(St.query(1, N).cnt == 1) cout << ans << endl;
    else cout << -1 << endl;
    return;
}


int main(){
#ifndef ONLINE_JUDGE
    freopen("z.txt", "r", stdin);
#endif
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);	
    
    int nofkase = 1;
	// cin >> nofkase;
	while(nofkase--) work();
	return 0;
}